
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "smbus.h"

#define USING_I2C_MODE

#define AP3216C_ADDR			0X1E	/* AP3216C 器件地址 */

/* AP3316C 寄存器 */
#define AP3216C_SYSTEMCONG		0x00	/* 配置寄存器 */
#define AP3216C_INTSTATUS		0X01	/* 中断状态寄存器 */
#define AP3216C_INTCLEAR		0X02	/* 中断清除寄存器 */
#define AP3216C_IRDATALOW		0x0A	/* IR 数据低字节 */
#define AP3216C_IRDATAHIGH		0x0B	/* IR 数据高字节 */
#define AP3216C_ALSDATALOW		0x0C	/* ALS 数据低字节 */
#define AP3216C_ALSDATAHIGH		0X0D	/* ALS 数据高字节 */
#define AP3216C_PSDATALOW		0X0E	/* PS 数据低字节 */
#define AP3216C_PSDATAHIGH		0X0F	/* PS 数据高字节 */

#ifdef USING_I2C_MODE
static int check_funcs(int file)
{
	unsigned long funcs;

	/* check adapter functionality */
	if (ioctl(file, I2C_FUNCS, &funcs) < 0)
		return -1;

	if (!(funcs & I2C_FUNC_I2C))
		return -1;

	return 0;
}

static int ap3216c_read_regs(int fd, uint8_t reg, uint8_t *data, uint8_t lenght)
{
	int nmsgs_sent;
	struct i2c_msg msg[2];
	struct i2c_rdwr_ioctl_data rdwr;

	//从机地址
	msg[0].addr = AP3216C_ADDR;
	//表示写
	msg[0].flags = 0;
	//buf是一个指针,指向了要发送的数据
	msg[0].buf = &reg;
	//msg[0].buf的数据长度
	msg[0].len = 1;

	msg[1].addr = AP3216C_ADDR;
	//表示读
	msg[1].flags = I2C_M_RD;
	msg[1].buf = data;
	msg[1].len = lenght;

	rdwr.msgs = msg;
	rdwr.nmsgs = 2;
	nmsgs_sent = ioctl(fd, I2C_RDWR, &rdwr);
	if (nmsgs_sent < 2) {
		return -1;
	}

	return 0;
}

static int ap3216c_write_regs(int fd, uint8_t reg, uint8_t *data, uint8_t lenght)
{
	int nmsgs_sent;
	uint8_t buffer[256];
	struct i2c_msg msg[1];
	struct i2c_rdwr_ioctl_data rdwr;
	
	//只能用一个msg发送，分多个msg时msg衔接的时候不会等待设备的ACK信号，可能会导致失败
	buffer[0] = reg;
	memcpy(&buffer[1], data, lenght);
	//从机地址
	msg[0].addr = AP3216C_ADDR;
	//表示写
	msg[0].flags = 0;
	//buf是一个指针,指向了要发送的数据
	msg[0].buf = buffer;
	//msg[0].buf的数据长度
	msg[0].len = 1 + lenght;

	rdwr.msgs = msg;
	rdwr.nmsgs = 1;
	nmsgs_sent = ioctl(fd, I2C_RDWR, &rdwr);
	if (nmsgs_sent < 1) {
		return -1;
	}

	return 0;
}

static int ap3216c_read_reg(int fd, uint8_t reg, uint8_t *data)
{
	return ap3216c_read_regs(fd, reg, data, 1);
}

static int ap3216c_write_reg(int fd, uint8_t reg, uint8_t data)
{
	return ap3216c_write_regs(fd, reg, &data, 1);
}

#else

static int check_funcs(int file)
{
	unsigned long funcs;

	/* check adapter functionality */
	if (ioctl(file, I2C_FUNCS, &funcs) < 0)
		return -1;

	if (!(funcs & I2C_SMBUS_BYTE_DATA))
		return -1;

	return 0;
}

static int ap3216c_read_reg(int fd, uint8_t reg, uint8_t *data)
{
	int result;

	result = i2c_smbus_read_byte_data(fd, reg);
	if(result < 0)
		return -1;
	*data = 0x0FF & result;
	return 0;
}

static int ap3216c_write_reg(int fd, uint8_t reg, uint8_t data)
{
	return i2c_smbus_write_byte_data(fd, reg, data);
}

#endif

static int ap3216c_init(int fd)
{
	int result;

	//初始化AP3216C，然后开启ALS、PS+IR
	result = ap3216c_write_reg(fd, AP3216C_SYSTEMCONG, 0x04);
	if(result != 0)
		return result;
	usleep(50*1000);
	result = ap3216c_write_reg(fd, AP3216C_SYSTEMCONG, 0X03);
	if(result != 0)
		return result;

	return 0;
}

static int ap3216c_read(int fd, uint16_t data[3])
{
	int i;
	int result;
	uint8_t buffer[6];

	/* 循环读取所有传感器数据 */
	for(i=0; i<6; i++) 
	{
		result = ap3216c_read_reg(fd, AP3216C_IRDATALOW+i, &buffer[i]);
		if(result != 0)
			return result;
	}

	if(buffer[0] & 0X80) {
		/* IR_OF位为1,则数据无效 */
		data[0] = 0;
	}
	else {
		/* 读取IR传感器的数据*/
		data[0] = ((uint16_t)buffer[1] << 2) | (buffer[0] & 0X03);
	}

	data[1] = ((uint16_t)buffer[3] << 8) | buffer[2]; /* 读取ALS传感器的数据 */

	if(buffer[4] & 0x40) {
		/* IR_OF位为1,则数据无效 */
		data[2] = 0;
	}
	else {
		/* 读取PS传感器的数据 */
		data[2] = ((uint16_t)(buffer[5] & 0X3F) << 4) | (buffer[4] & 0X0F);
	}

	return 0;
}

static int open_i2c_dev(uint32_t i2cbus)
{
	int file, len;
	char filename[32];

	len = snprintf(filename, sizeof(filename), "/dev/i2c/%d", i2cbus);
	if (len >= sizeof(filename)) {
		return -1;
	}
	file = open(filename, O_RDWR);

	if(file < 0 && (errno == ENOENT || errno == ENOTDIR)) {
		len = snprintf(filename, sizeof(filename), "/dev/i2c-%d", i2cbus);
		if (len >= sizeof(filename))
			return -1;
		file = open(filename, O_RDWR);
	}

	return file;
}

static int set_slave_addr(int file, int address, int force)
{
	/* With force, let the user read from/write to the registers
	   even when a driver is also running */
	if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0)
		return -1;

	return 0;
}

int main(int argc, char *argv[])
{
	int file;
	int result;
	uint16_t ir, als, ps;
	uint32_t i2cbus;
	uint16_t databuf[3];

#ifdef USING_I2C_MODE
	printf("i2c mode\n");
#else
	printf("smbus mode\n");
#endif

	i2cbus = 0;
	if(argc > 1)
		i2cbus = strtoul(argv[1], NULL, 0);

	//打开I2C控制器
	file = open_i2c_dev(i2cbus);
	if (file < 0) {
		fprintf(stderr, "Error: open i2c bus failed");
		return -1;
	}

	//检查适配器是否支持
	result = check_funcs(file);
	if(result < 0) {
		fprintf(stderr, "Error: Adapter does not have capability");
		return -1;
	}

	//设置从机地址
	result = set_slave_addr(file, AP3216C_ADDR, 1);
	if(result < 0) {
		fprintf(stderr,
			"Error: Could not set address to 0x%02x: %s\n",
			AP3216C_ADDR, strerror(errno));
		return -1;
	}

	//初始化AP3216C
	result = ap3216c_init(file);
	if(result < 0) {
		fprintf(stderr, "Error: initial ap3216 failed");
		return -1;
	}
	while(1)
	{
		/*200ms */
		usleep(200000);

		result = ap3216c_read(file, databuf);
		if(result == 0)
		{
			/* 数据读取成功 */
			ir =  databuf[0];	/* ir传感器数据 */
			als = databuf[1];	/* als传感器数据 */
			ps =  databuf[2];	/* ps传感器数据 */
			printf("ir = %d, als = %d, ps = %d\r\n", ir, als, ps);
		}
		else
			fprintf(stderr, "Error: read data failed");
	}

	/* 关闭文件 */
	close(file);
	return 0;
}